﻿using Fuse8.ContentManagementFramework.BizFacade.Services;
using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Special;
using Fuse8.DomainFramework.BusinessService;
using Fuse8.DomainFramework.Common.Locator;
using System;
using System.Linq;

namespace Fuse8.ContentManagementFramework.BizFacade
{
    /// <summary>
    /// Contract for CmsPage URL resolver
    /// </summary>
    public interface ICmsPageUrlResolver
    {
        /// <summary>
        /// Gets url for specified page
        /// </summary>
        /// <param name="page">Page to resolve URL</param>
        /// <returns></returns>
        string GetUrl(CmsPage page);
    }

    /// <summary>
    /// Default implementation of <see cref="ICmsPageUrlResolver"/>
    /// </summary>
    /// <remarks>Uses <see cref="CmsPageService"/> to find child and redirect target pages</remarks>
    public class DefaultCmsPageUrlResolver : ICmsPageUrlResolver
    {
        private readonly CmsPageService pageService;

        internal DefaultCmsPageUrlResolver(CmsPageService service)
        {
            pageService = service;
        }

        public DefaultCmsPageUrlResolver()
        {
            pageService = new CmsPageService();
        }

        public virtual string GetUrl(CmsPage page)
        {
            if (page == null)
            {
                return null;
            }

            switch (page.BehaviourPageType)
            {
                case CmsPageBehaviourTypeKind.Content:
                    return page.PageUrl;

                case CmsPageBehaviourTypeKind.Placeholder:
                    return GetPlaceholderTarget(page);

                case CmsPageBehaviourTypeKind.Redirect:
                    return GetRedirectTarget(page);

                default:
                    return null;
            }
        }

        protected virtual string GetPlaceholderTarget(CmsPage page)
        {
            var children = pageService.GetChildPages(page.Id);
            return GetUrl(children.FirstOrDefault(p => p.IsVisible && p.IsPublished));
        }

        protected virtual string GetRedirectTarget(CmsPage page)
        {
            var setting = page.RedirectSetting;
            if (setting != null)
            {
                switch (setting.Type)
                {
                    case PageRedirectKind.PresentOnly:
                        if (!string.IsNullOrEmpty(setting.UrlToRedirect))
                        {
                            return setting.UrlToRedirect;
                        }
                        if (setting.PublicPageIdToRedirect.HasValue)
                        {
                            return GetUrl(pageService.FindByPublicId(setting.PublicPageIdToRedirect.Value));
                        }
                        break;

                    case PageRedirectKind.Redirect301:
                    case PageRedirectKind.Redirect302:
                        return page.PageUrl;
                }
            }
            return null;
        }
    }

    /// <summary>
    /// Provides methods to get page URL
    /// </summary>
    public class CmsUrlManager
    {
        private static readonly CmsPageService cmsPageService = new CmsPageService();
        public const string PreDefinedfinedPageNotFoundUrl = "/404";

        /// <summary>
        /// Gets page url by unique id
        /// </summary>
        /// <param name="pageId">Unique page id</param>
        /// <returns>Page Url or /404 if page not found</returns>
        public static string GetUrlByPageId(int pageId)
        {
            return GetUrlByPage(cmsPageService.FindOne(pageId));
        }

        /// <summary>
        /// Gets page url by public id
        /// </summary>
        /// <param name="publicPageId">Public page id</param>
        /// <returns>Page Url or /404 if page not found</returns>
        public static string GetUrlByPagePublicId(int publicPageId)
        {
            return GetUrlByPage(cmsPageService.FindByPublicId(publicPageId));
        }

        /// <summary>
        /// Gets page url by public id
        /// </summary>
        /// <param name="pageKey">Public page id</param>
        /// <returns>Page Url or /404 if page not found</returns>
        public static string GetUrlByPageKey(string pageKey)
        {
            return GetUrlByPage(cmsPageService.FindByPageKey(pageKey));
        }

        /// <summary>
        /// Gets page url by page
        /// </summary>
        /// <param name="page">Page id</param>
        /// <returns>Page Url or /404 if page is null</returns>
        public static string GetUrlByPage(CmsPage page)
        {
            string result = PreDefinedfinedPageNotFoundUrl;
            if (page != null)
            {
                var context = DependencyServiceLocator.Current.GetInstance<ICmsContext>();

                string key = "CmsPageUrl::" + page.Id;
                if (context.ContextItems.Contains(key))
                {
                    result = context.ContextItems[key].ToString();
                }
                else
                {
                    var urlByPage = DependencyServiceLocator.Current.GetInstance<ICmsPageUrlResolver>().GetUrl(page);
                    if (!string.IsNullOrEmpty(urlByPage))
                    {
                        context.ContextItems[key] = urlByPage;

                        result = urlByPage;
                    }
                }
            }

            return result;
        }
    }
}